Expand description
Lock-free SPSC FIFO ring buffer with direct access to inner data.
Features
- Lock-free operations - they succeed or fail immediately without blocking or waiting.
- Arbitrary item type (not only
Copy
). - Items can be inserted and removed one by one or many at once.
- Thread-safe direct access to the internal ring buffer memory.
Read
andWrite
implementation.- Can be used without
std
and even withoutalloc
(using only statically-allocated memory). - Experimental
async
/.await
support.
Usage
At first you need to create the ring buffer itself. HeapRb
is recommended but you may choose another one.
After the ring buffer is created it may be splitted into pair of Producer
and Consumer
.
Producer
is used to insert items to the ring buffer, Consumer
- to remove items from it.
For SharedRb
and its derivatives they can be used in different threads.
Also you can use the ring buffer without splitting at all via methods provided by Rb
trait.
Types
There are several types of ring buffers provided:
Performance
SharedRb
needs to synchronize CPU cache between CPU cores. This synchronization has some overhead.
To avoid multiple unnecessary synchronizations you may use postponed mode of operation (see description for Producer
and Consumer
)
or methods that operate many items at once (Producer::push_slice
/Producer::push_iter
, Consumer::pop_slice
, etc.).
For single-threaded usage LocalRb
is recommended because it is faster than SharedRb
due to absence of CPU cache synchronization.
Benchmarks
You may see typical performance of different methods in benchmarks:
cargo +nightly bench --features bench
Nightly toolchain is required.
Examples
Simple
use ringbuf::HeapRb;
let rb = HeapRb::<i32>::new(2);
let (mut prod, mut cons) = rb.split();
prod.push(0).unwrap();
prod.push(1).unwrap();
assert_eq!(prod.push(2), Err(2));
assert_eq!(cons.pop(), Some(0));
prod.push(2).unwrap();
assert_eq!(cons.pop(), Some(1));
assert_eq!(cons.pop(), Some(2));
assert_eq!(cons.pop(), None);
No heap
use ringbuf::StaticRb;
const RB_SIZE: usize = 1;
let mut rb = StaticRb::<i32, RB_SIZE>::default();
let (mut prod, mut cons) = rb.split_ref();
assert_eq!(prod.push(123), Ok(()));
assert_eq!(prod.push(321), Err(321));
assert_eq!(cons.pop(), Some(123));
assert_eq!(cons.pop(), None);
Overwrite
Ring buffer can be used in overwriting mode when insertion overwrites the latest element if the buffer is full.
use ringbuf::{HeapRb, Rb};
let mut rb = HeapRb::<i32>::new(2);
assert_eq!(rb.push_overwrite(0), None);
assert_eq!(rb.push_overwrite(1), None);
assert_eq!(rb.push_overwrite(2), Some(0));
assert_eq!(rb.pop(), Some(1));
assert_eq!(rb.pop(), Some(2));
assert_eq!(rb.pop(), None);
Note that push_overwrite
requires exclusive access to the ring buffer
so to perform it concurrently you need to guard the ring buffer with Mutex
or some other lock.
async
/.await
There is an experimental crate async-ringbuf
which is built on top of ringbuf
and implements asynchronous ring buffer operations.
Re-exports
Modules
Structs
- Ring buffer for using in single thread.
- Ring buffer that could be shared between threads.
Traits
- An abstract ring buffer.
Functions
- Moves at most
count
items from thesrc
consumer to thedst
producer.
Type Definitions
- Heap-allocated ring buffer.
- Stack-allocated ring buffer with static capacity.